﻿using AutoMapper;
using HamcoWcs.Contract.ContractCommon;
using HamcoWcs.Contract.ContractLcd;
using HamcoWcs.DAL;
using HamcoWcs.Entitys.BaseConfigs;
using HamcoWcs.Entitys.PalletInfos;
using HamcoWcs.Models.ForeEndModels.Wms;
using HamcoWcs.Models.LcdInfos;
using HamcoWcs.Models.NodeInfos;
using HamcoWcs.Service.Common;
using Microsoft.EntityFrameworkCore;
using Quartz;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace HamcoWcs.Workers
{
    /// <summary>显示屏数据服务</summary>
    [DisallowConcurrentExecution]
    public class LcdWorker : WorkerBase
    {
        private void DoWork()
        {
            var lcds = _lcd.LcdDic;
            foreach (var k in lcds.Keys)
            {
                var lcd = lcds[k];
                var node = _asrs.Nodes.FirstOrDefault(x => x.NodeName == k);
                InitLcdInfo(lcd, node, out string w);

                if (!(w == "入库模式" || w == "出库模式")) continue;

                var state = lcd.Msgs.FirstOrDefault(x => x.Key == "状态");
                state.Value = "";

                // 异常显示
                if (node.Pcons.Any(x => x.PconMode == 4))
                {
                    AlarmExplanation alarm1 = null;

                    if (node.Pcons[0].ErrorCode > 0)
                    {
                        alarm1 = AutomaticStorageInfo.Alarms.FirstOrDefault(x => x.Module == "pcon" && x.Code == node.Pcons[0].ErrorCode.ToString()) ?? new AlarmExplanation()
                        {
                            AlarmName = "未知异常"
                        };
                    }

                    AlarmExplanation alarm2 = null;

                    if (node.Pcons[1].ErrorCode > 0)
                    {
                        alarm2 = AutomaticStorageInfo.Alarms.FirstOrDefault(x => x.Module == "pcon" && x.Code == node.Pcons[1].ErrorCode.ToString()) ?? new AlarmExplanation()
                        {
                            AlarmName = "未知异常"
                        };
                    }

                    if (alarm1 != null && alarm2 != null)
                    {
                        state.Value = $"{alarm1.AlarmName};{alarm2.AlarmName}";
                    }
                    else if (alarm1 is null)
                    {
                        state.Value = $"{alarm2.AlarmName}";
                    }
                    else if (alarm2 is null)
                    {
                        state.Value = $"{alarm1.AlarmName}";
                    }
                    else
                    {
                        state.Value = "";
                    }
                }
                // 退回
                else if (node.Pcons.Any(x => x.CheckResult != 0))
                {
                    var c = node.Pcons.FirstOrDefault(x => x.CheckResult != 0)?.CheckResult ?? 0;
                    var cStr = GetCheckResult(c);
                    state.Value = cStr;
                }
                // 工作模式
                else
                {
                    if (w == "入库模式")
                    {
                        var aisle = "";
                        if (k == "CJRCV100" || k == "CJRCV200")
                            aisle = "CJSTW200";
                        if (k == "CJRCV300" || k == "CJRCV400")
                            aisle = "CJSTW100";

                        var locs = _wcsDbContext.WcsLocations
                            .AsNoTracking()
                            .Where(x => x.LocType == "shelf")
                            .Where(x => x.Aisle == aisle)
                            .Where(x => !string.IsNullOrEmpty(x.UnitId))
                            .ToList();

                        var uilocs = _mapper.Map<List<UILocInfo>>(locs);

                        var pallets = _wcsDbContext.Set<PalletInfo>()
                            .AsNoTracking()
                            .Where(x => x.PalletType == "EMPTYBOX")
                            .ToDictionary(k => k.UnitId, v => v);

                        foreach (var loc in uilocs)
                        {
                            var a = pallets.TryGetValue(loc.UnitId, out PalletInfo pallet);
                            if (a)
                            {
                                loc.PalletType = pallet.PalletType;
                                loc.Size = pallet.Size;
                            }
                            else
                            {
                                loc.Size = "";
                            }
                        }

                        SetMesStockerInfo(lcd, aisle);
                    }
                    else if (w == "出库模式")
                    {
                        var con = node.Pcons.FirstOrDefault(x => x.PortName == "01");

                        var palletNameMsg = lcd.Msgs.FirstOrDefault(x => x.Key == "栈板号");
                        var orderNumberMsg = lcd.Msgs.FirstOrDefault(x => x.Key == "预留单号");
                        var numberMsg = lcd.Msgs.FirstOrDefault(x => x.Key == "剩余数量");
                        if (!string.IsNullOrEmpty(con.UnitId) && con.IsGoods == 1)
                        {
                            palletNameMsg.Value = con.UnitId;

                            var orderId = _wcsDbContext.Set<PalletInfo>()
                                .Where(x => x.UnitId == con.UnitId)
                                .FirstOrDefault()?.OrderNumber ?? "未找到预留单号";

                            orderNumberMsg.Value = orderId;

                            var count = _wcsDbContext.Set<PalletInfo>()
                                .Where(x => x.OrderNumber == orderId).Count();
                            numberMsg.Value = count.ToString();
                        }
                        else
                        {
                            if (con.PconMode != 6)
                            {
                                palletNameMsg.Value = "";
                                orderNumberMsg.Value = "";
                                numberMsg.Value = "";
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 设置MES Stocker计划信息
        /// </summary>
        /// <param name="lcd">Lcd对象</param>
        /// <param name="aisle">巷道</param>
        private void SetMesStockerInfo(LcdInfoDto lcd, string aisle)
        {
            var dic = StockerPlanInfo.StockerPlanDic[aisle];

            var waterLevel = lcd.Msgs.FirstOrDefault(x => x.Key == "投入包材");
            var b1 = dic["43"].InputQty;
            var b2 = dic["65"].InputQty;
            var b3 = dic["75"].InputQty;
            var b4 = dic["85"].InputQty;

            waterLevel.Value = $"{PadWebSpaceRight(b1.ToString(), 3)}|{PadWebSpaceRight(b2.ToString(), 3)}|{PadWebSpaceRight(b3.ToString(), 3)}|{PadWebSpaceRight(b4.ToString(), 3)}";

            var planNumber = lcd.Msgs.FirstOrDefault(x => x.Key == "计划包材");
            var c1 = dic["43"].PlanQty;
            var c2 = dic["65"].PlanQty;
            var c3 = dic["75"].PlanQty;
            var c4 = dic["85"].PlanQty;

            planNumber.Value = $"{PadWebSpaceRight(c1.ToString(), 3)}|{PadWebSpaceRight(c2.ToString(), 3)}|{PadWebSpaceRight(c3.ToString(), 3)}|{PadWebSpaceRight(c4.ToString(), 3)}";
        }

        /// <summary>
        /// 填充Web空格
        /// </summary>
        /// <param name="s">字符串</param>
        /// <param name="width">字体需要宽度</param>
        /// <returns>填充空格的字符</returns>
        private string PadWebSpaceRight(string s, int width)
        {
            if (string.IsNullOrEmpty(s)) return "";


            if (s.Length > width) return s;
            var w = width - s.Length;
            for (int i = 0; i < w * 2 - 1; i++)
            {
                s = s + "&nbsp;";
            }
            return s;
        }

        /// <summary>
        /// 获取退回信息<br/>
        /// 1=超高，2=左超宽，3=右超宽，4=前超长，5=后超长，6=读码异常, 7=WCS拒绝
        /// </summary>
        /// <param name="w">PLC->WCS ErrorCode</param>
        /// <returns>ErrorCode String</returns>
        private string GetCheckResult(int w) => w switch
        {
            01 => "超高",
            02 => "左超宽",
            03 => "右超宽",
            04 => "前超长",
            05 => "后超长",
            06 => "读码异常",
            07 => "WCS/MES拒",
            08 => "WCS读取扫码信息异常",
            09 => "栈板类型错误",
            10 => "MES拒绝切换栈板类型",
            11 => "库位中已有相同栈板号",
            12 => "MES拒绝入库",
            13 => "立库爆仓退回",
            14 => "栈板/条码尺寸不符",
            15 => "栈板/BOX尺寸不符",
            _ => "未知退回原因"
        };

        /// <summary>
        /// 获取设备工作模式<br/>
        /// 1:入库模式,2:出库模式,3:双向模式,4:人工投料
        /// </summary>
        /// <param name="w">PLC->WCS WorkType</param>
        /// <returns>WorkType String</returns>
        private string GetWorkType(int w) => w switch
        {
            1 => "入库模式",
            2 => "出库模式",
            3 => "双向模式",
            4 => "人工投料",
            _ => "未知模式",
        };

        /// <summary>
        /// 初始化Lcd字段信息
        /// </summary>
        /// <param name="lcd">lcd对象</param>
        /// <param name="node">节点</param>
        /// <param name="w">PLC工作模式</param>
        private void InitLcdInfo(LcdInfoDto lcd, NodeInfoDto node, out string w)
        {
            var workType = lcd.Msgs.FirstOrDefault(x => x.Key == "工作模式");
            w = GetWorkType(node.Pcons[0].WorkType);

            if (workType.Value != w)
            {
                if (w == "入库模式")
                {
                    lcd.Msgs = new List<LcdMsg>()
                    {
                        new LcdMsg() {Key="名称" ,Value=node.NodeName},
                        new LcdMsg() {Key="工作模式" ,Value=w},
                        new LcdMsg() {Key="包材规格" ,Value=$"43 |65 |75 |85 "},
                        new LcdMsg() {Key="计划包材" ,Value=""},
                        new LcdMsg() {Key="投入包材" ,Value=""},
                        new LcdMsg() {Key="状态" ,Value=""},
                    };
                }
                if (w == "出库模式")
                {
                    lcd.Msgs = new List<LcdMsg>()
                    {
                        new LcdMsg() {Key="名称" ,Value=node.NodeName},
                        new LcdMsg() {Key="工作模式" ,Value=w},
                        new LcdMsg() {Key="预留单号" ,Value=""},
                        new LcdMsg() {Key="剩余数量" ,Value=""},
                        new LcdMsg() {Key="栈板号" ,Value=""},
                        new LcdMsg() {Key="状态" ,Value=""},
                    };
                }

            }

        }

        public override Task Execute(IJobExecutionContext context)
        {
            try
            {
                DoWork();
            }
            catch (Exception ex)
            {
                _logger.AddSystemErrorLog($"LcdWorker:{ex.Message}");
            }

            return Task.CompletedTask;
        }

        private readonly ILcdService _lcd;
        private readonly AutomaticStorageInfo _asrs;
        public LcdWorker(ILcdService lcd, AutomaticStorageInfo asrs, WcsDbContext wcsDbContext, IMapper mapper, ILoggerService logger) : base(wcsDbContext, mapper, logger)
        {
            _lcd = lcd;
            _asrs = asrs;
        }
    }
}
